#include <iostream>
#include <vector>
#include <string>

#include <boost/asio.hpp>
#include <boost/bind.hpp>

#include "dispatch_connection.h" // Must come before boost/serialization headers.
#include "client_rpcs.h"

#include "remote_grep.h"

/// Downloads stock quote information from a server.
class grep_client
{
public:
  /// Constructor starts the asynchronous connect operation.
  grep_client(boost::asio::io_service& io_service,
      const std::string& host, const std::string& service,const std::string& args)
    : connection_(new dispatch_connection(io_service)),grep_(args)
  {

	send_handler_ = std::nullptr_t();
	write_handler_ = std::nullptr_t();
    // Resolve the host name into an IP address.
    boost::asio::ip::tcp::resolver resolver(io_service);
    boost::asio::ip::tcp::resolver::query query(host, service);
    boost::asio::ip::tcp::resolver::iterator endpoint_iterator =
      resolver.resolve(query);
    boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator;

    // Start an asynchronous connect operation.
    connection_->socket().async_connect(endpoint,
        boost::bind(&grep_client::handle_connect, this,
          boost::asio::placeholders::error, ++endpoint_iterator));
  }
  ~grep_client(){delete send_handler_;delete write_handler_;}
  /// Handle completion of a connect operation.
  void handle_connect(const boost::system::error_code& e,
      boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
  {
    if (!e)
    {
		//todo: send current rpc
		if(!write_handler_)
		{
			write_handler_ =new std::function<void(const boost::system::error_code& ,const std::vector<char>)> 
			([=](const boost::system::error_code& e,const std::vector<char>& v)
		{
			if(!e)
				connection_->handle_write(e,v,*this->send_handler_);	
			else
				std::cerr<<e.message()<<std::endl;
		});
		}
		if(!send_handler_)
		{
			send_handler_ =new std::function<void(const boost::system::error_code& ,dispatch_connection_ptr)> 
			([=](const boost::system::error_code& error,dispatch_connection_ptr conn)
		{
			if(!error)
			{
				conn->start(*this->send_handler_);
			}
			else{
				std::cerr<<error.message()<<std::endl;
			}
		});
		}
		grep_.send_command(*write_handler_);
    }
    else if (endpoint_iterator != boost::asio::ip::tcp::resolver::iterator())
    {
      // Try the next endpoint.
      connection_->socket().close();
      boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
      connection_->socket().async_connect(endpoint,
          boost::bind(&grep_client::handle_connect, this,
            boost::asio::placeholders::error, ++endpoint_iterator));
    }
    else
    {
      // An error occurred. Log it and return. Since we are not starting a new
      // operation the io_service will run out of work to do and the client will
      // exit.
      std::cerr << e.message() << std::endl;
    }
  }

  /// Handle completion of a read operation.
  void handle_read(const boost::system::error_code& e)
  {
    if (!e)
    {
		//todo display result
    }
    else
    {
      // An error occurred.
      std::cerr << e.message() << std::endl;
    }

    // Since we are not starting a new operation the io_service will run out of
    // work to do and the client will exit.
  }

private:
  /// The connection to the server.
  dispatch_connection_ptr connection_;
  
  std::function<void(const boost::system::error_code& ,dispatch_connection_ptr)>* send_handler_;
  std::function<void(const boost::system::error_code& ,const std::vector<char>)>* write_handler_;

  remote_grep grep_;
};
int main(int argc,char* argv[])
{
  try
  {
	const char* host = "127.0.0.1";
	const char* port = "10086";
    boost::asio::io_service io_service;
	std::string args;
	for(int i = 1;i < argc; ++i)
	{
		args += argv[i];
		args += " ";
	}
    grep_client client(io_service, host, port,args);
    io_service.run();
  }
  catch (std::exception& e)
  {
    std::cerr << e.what() << std::endl;
  }

  return 0;
}